// file: arch/x86/include/arch/smbios.h
// autor: jiangxinpeng
// time: 2021.2.16
// copyright: (C) 2020-2050 by jiangxinpeng,All right are reserved.

#ifndef ARCH_SMBIOS_H
#define ARCH_SMBIOS_H

#include <arch/pymem.h>
#include <arch/arch.h>

#define BIOS_BASE_START ((uint32_t)(0xf0000 + PAGE_HIGH_BASE))
#define BIOS_BASE_END ((uint32_t)(0xfffff + PAGE_HIGH_BASE))

#ifdef __ARCH_X86
#define SMBIOS_EPT_SIGN "_SM_"
#pragma packed(push, 1)
// smbios ver 3.0 and later
typedef struct
{
    char entrystring1[4]; // must be "_SM_"
    uint8_t checksum1;    // checksum just is all byte add,must be 0
    uint8_t length;       // enter point table length
    uint8_t major_version;
    uint8_t minor_version;
    uint8_t max_size;        // max struct size
    uint8_t smbios_revision; // smbios reversion
    uint8_t formatted_area[5];
    uint8_t entrystring2[5];  // must be "_DMI"
    uint8_t checksum2;        // DMI checksum,from string "_DMI" to EPT end
    uint16_t table_total_len; // struct table total len
    uint32_t table_point;     // table base point
    uint16_t table_num;       // table count
    uint8_t bcd_revision;     // smbios revision
} smbios_t;
#pragma packed(pop)
#elif __ARCH_X64
#define SMBIOS_EPT_SIGN "_SM3_"
#pragma packed(push, 1)
typedef struct
{
    uint8_t entrystring[5]; // must be _SM3_
    uint8_t checksum;       // checksum
    uint8_t length;         // entry point length
    uint8_t major_version;
    uint8_t minor_version;
    uint8_t docrev;
    uint8_t revision;
    uint8_t reserved;
    uint32_t table_total_len; // max struct size
    uint64_t table_point;     // table base point
};
#pragma packed(pop)
#else
#error "arch config error!"
#endif

#pragma packed(push, 1)
typedef struct
{
    uint8_t type;
    uint8_t length;
    uint8_t handler;
} smbios_struct_header_t;
#pragma packed(pop)

typedef enum
{
    BIOS_Info = 0,
    System_Info = 1,
    Baseboard_Info = 2,
    System_Enclosure = 3,
    Processor_Info = 4,
    Cache_Info = 7,
    System_Slots = 9,
    Phy_Mem_Array = 16,
    Memory_Device = 17,
    Memory_Array_Mapped_Address = 19,
    System_Boot_Information = 32,
} smbios_struct_type_t;

#define TABLE_TYPE(table) ((table)->type)
#define TABLE_LEN(table) ((table)->length)
#define TABLE_HANDLER(table) ((table)->handler)


#pragma packed(push, 1)
typedef struct smbios_table_bios
{
    uint8_t type;   // bios type indiate
    uint8_t length; // bios character bytes
    uint16_t handle;
    uint8_t vendor;                // bios vendor string
    uint8_t version;               // bios version string
    uint16_t start_addr;           // bios start address segment string
    uint8_t release_date;          // bios release date
    uint8_t rom_size;              // bios rom size
    uint64_t support;              // bios support function define
    uint8_t extension[2];          // bios externsion
    uint8_t sysbios_major_release; // idenitifies the major release of the sytem bios
    uint8_t sysbios_minor_release; // idenitifies the minor relaes of the system bios
    uint8_t ctrlfw_major_release;  // idenitifies the major relase of the embedded controller fireware
    uint8_t ctrlfw_minor_release;  // idenitifies the minor relase of the embedded controller fireware
    uint16_t extendbios_rom_size;  // extended size of bios
} smbios_table_bios_t;
#pragma packed(pop)



#define SMBIOS_BIOS_CHAR_NOSUPPORT 0x8
#define SMBIOS_BIOS_ISA_SUPPORT 0x10
#define SMBIOS_BIOS_MCA_SUPPORT 0x20
#define SMBIOS_BIOS_EISA_SUPPORT 0x40
#define SMBIOS_BIOS_PCI_SUPPORT 0x80
#define SMBIOS_BIOS_PCMCIA_SUPPORT 0x100
#define SMBIOS_BIOS_PLUS_PLAY_SUPPORT 0x200
#define SMBIOS_BIOS_APM_SUPPORT 0x400
#define SMBIOS_BIOS_FLASH 0x800
#define SMBIOS_BIOS_SHADOW_ALLOW 0x1000
#define SMBIOS_BIOS_VL_VESA_SUPPORT 0x2000
#define SMBIOS_BIOS_ESCD_SUPPORT 0x4000
#define SMBIOS_BIOS_CDBOOT_SUPPORT 0x8000
#define SMBIOS_BIOS_SELECTBOOT_SUPPORT 0x10000
#define SMBIOS_BIOS_BIOSROM_SOCKET 0x20000
#define SMBIOS_BIOS_PCMCIABOOT_SUPPORT 0x40000
#define SMBIOS_BIOS_EDD_SUPPORT 0x80000
#define SMBIOS_BIOS_NEC_PC -98 0x80000000

#define SMBIOS_BIOSEX1_ACPI_SUPPORT 0x1
#define SMBIOS_BIOSEX1_USBLEGACY_SUPPORT 0x02
#define SMBIOS_BIOSEX1_AGP_SUPPORT 0x04
#define SMBIOS_BIOSEX1_12O_BOOT_SUPPORT 0x08
#define SMBIOS_BIOSEX1_LS120_SUPERDISK_BOOT_SUPPORT 0x10
#define SMBIOS_BIOSEX1_ATAPI_ZIP_BOOT_SUPPORT 0x20
#define SMBIOS_BIOSEX1_1394_BOOT_SUPPORT 0x40
#define SMBIOS_BIOSEX1_SMARTBATTERY_SUPPORT 0x80

#define SMBIOS_BIOSEX2_BIOSBOOT_SUPPORT 0x01
#define SMBIOS_BIOSEX2_NETSERVBOOT_SUPPORT 0x02
#define SMBIOS_BIOSEX2_CONTENT_DISTRIBUTION 0x04
#define SMBIOS_BIOSEX2_UEFIBOOT_SUPPORT 0x08
#define SMBIOS_BIOSEX2_VIRTUALMACHINE 0x10

#pragma packed((push, 1))
typedef struct
{
    uint8_t type;
    uint8_t length;
    uint16_t handle;
    uint8_t manufacturer;
    uint8_t product_name;
    uint8_t version;
    uint8_t serial_number;
    uint8_t UUID[16];
    uint8_t wakeup_type; // identifies the events that can cause the sytem to power up
    uint8_t SKU_number;
    uint8_t family;
} smbios_table_syteminfo_t;
#pragma packed(pop)

#pragma packed((push, 1))
typedef struct
{
    uint8_t type;
    uint8_t length;
    uint16_t handle;
    uint8_t manufacturer;
    uint8_t product;
    uint8_t version;
    uint8_t serial_number;
    uint8_t asset_tag;
    uint8_t feature_flags;
    uint8_t location_chassic;
    uint8_t chassic_handle;
    uint8_t board_type;
} smbios_table_baseboard_info_t;
#pragma packed((pop))

#pragma packed((push, 1))
typedef struct
{
    uint8_t type;
    uint8_t length;
    uint16_t handle;
    uint8_t manufacturer;
    uint8_t enclosure_type;
    uint8_t version;
    uint8_t serial_num;
    uint8_t asset_tag;
    uint8_t bootup_status;
    uint8_t power_status;
    uint8_t thermal_status;
    uint8_t security_status;
    uint16_t oem;
    uint8_t height;
    uint8_t num_of_power;
    uint8_t element_count;
} smbios_table_system_enclosure_classic_t;
#pragma packed(pop)

extern smbios_t *smbios;

#define SMBIOS_TABLE ((void *)smbios)

// function
void SmbiosInit();
__attribute((optimize("O0"))) void *SmBiosGetEntry();
__attribute((optimize("O0"))) char *SmbiosGetVerStr(char *str, int len);
__attribute((optimize("O0"))) smbios_struct_header_t *SmbiosGetTable(smbios_t *smbios, int type);
__attribute((optimize("O0"))) char *SmbiosGetString(smbios_struct_header_t *header);
__attribute((optimize("O0"))) char *SmbiosFindStr(smbios_struct_header_t *header, int idx);
__attribute((optimize("O0"))) uint32_t SmbiosGetStrLen(smbios_struct_header_t *header);
void SmbiosBiosPrint();
void SmbiosDump();
#endif